﻿using System.Drawing;
using CanvasControl.Model;
using CanvasControl.View;
using GraphDrawing.Graph.Model;
using GraphDrawing.Graph.View;

namespace GraphDrawing.Graph.Behaviors
{
    /// <summary>
    /// Состояние создания связей между слотами элементов.
    /// </summary>
    public class LinkingStatePresenter : ModelStatePresenter, IPainter
    {
        /// <summary>
        /// Точка начала линии.
        /// </summary>
        readonly Point startPoint;

        /// <summary>
        /// Модель слота, из которого создаётся связь.
        /// </summary>
        readonly SlotModel slot;

        /// <summary>
        /// Точка конца линии.
        /// </summary>
        Point endPoint;

        public LinkingStatePresenter(ModelStateContext context, SlotModel slot) : base(context)
        {
            this.slot = slot;
            var rect = slot.GetBounds();
            endPoint = startPoint = context.CanvasModel.ViewPort.GlobalToClient(new Point(rect.X + rect.Width/2, rect.Y + rect.Height/2));
            MarkSlots();
            context.CanvasModel.AddPainter(PaintStages.POSTPROCESSING, this);
            context.Canvas.UpdateView();
        }

        public override void OnMouseUp(Point p)
        {
            var graph = context.Graph;
            var viewPoint = context.CanvasModel.ViewPort.ClientToGlobal(p);
            var hitTest = graph.HitTest(viewPoint, context.CanvasModel.ViewPort.IsVisible);
            if (hitTest.hitType == HitType.SLOT && graph.CanConnect(slot, hitTest.slot))
                graph.Connect(slot, hitTest.slot);
            foreach (var b in graph.EnumerateBlocks())
            foreach (var s in b.Slots)
                s.state = SlotState.DEFAULT;
            context.CanvasModel.RemovePainter(this);
        }

        public override void OnMouseMove(Point p)
        {
            endPoint = p;
            context.Canvas.UpdateView();
        }

        public void Draw(DrawingContext dc)
        {
            var view = context.ViewContainer.GetView<ILinkingView>();
            view.Draw(dc, LineShapeType.BEZIER, startPoint, endPoint);
        }

        /// <summary>
        /// Проверяет слоты блоков, отличных от текущего, может ли быть установлено соединение между ними и текущим слотом.
        /// Устанавливает состояния слотов.
        /// </summary>
        void MarkSlots()
        {
            foreach (var otherBlock in context.Graph.EnumerateBlocks())
            foreach (var otherSlot in otherBlock.Slots)
                otherSlot.state = context.Graph.CanConnect(slot, otherSlot) ? SlotState.ACCEPTABLE : SlotState.UNACCEPTABLE;
            slot.state = SlotState.PRESSED;
        }
    }
}